<template>
  <div class="scroll-wrapper" ref="scroll" :style="height">
    <div class="scroll-content">
      <div class="pull-down-wrapper" v-if="bScrollObject.pullDownRefresh">
        <div v-html="downTipText"></div>
      </div>
      <slot></slot>
    </div>
    <div class="back-to-top" v-show="bScrollObject.showBackToTop && showBackToTop" @click="backToTop">
      <img src="~@/assets/img/common/top.png" alt="">
    </div>
  </div>
</template>

<script>
import BScroll from "better-scroll";
import {__debounce} from "@/common/utils";
import {BScrollClass} from "@/common/constant";

// pullDownRefresh state
const PHASE = {
  moving: {
    enter: 'enter',
    leave: 'leave'
  },
  fetching: 'fetching',
  succeed: 'succeed'
}
const ARROW_BOTTOM = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M367.997 338.75l-95.998 95.997V17.503h-32v417.242l-95.996-95.995l-22.627 22.627L256 496l134.624-134.623l-22.627-22.627z"></path></svg>'
const ARROW_UP = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M390.624 150.625L256 16L121.376 150.625l22.628 22.627l95.997-95.998v417.982h32V77.257l95.995 95.995l22.628-22.627z"></path></svg>'

export default {
  name: "BScroll",
  props: {
    bScrollObject: {
      type: BScrollClass,
      default() {
        return BScrollClass
      }
    }
  },
  data() {
    return {
      bScroll: null,
      showBackToTop: false,
      downTipText: '',
      timeId: null
    }
  },
  mounted() {
    this.__initBScroll();
    let debounceRefresh = __debounce(this.refresh, 50);
    this.$bus.$on(this.bScrollObject.imgLoadFunName, () => {
      debounceRefresh();
    });
  },
  computed: {
    height() {
      if (this.bScrollObject && this.bScrollObject.excessHeight) {
        return {height: 'calc(100% - ' + this.bScrollObject.excessHeight + 'px)'};
      }
      return '';
    }
  },
  methods: {
    __initBScroll() {
      this.bScroll = new BScroll(this.$refs.scroll, {
        click: true,
        probeType: this.bScrollObject.probeType,
        pullDownRefresh: this.bScrollObject.pullDownRefresh,
        pullUpLoad: (this.bScrollObject.pullUpLoad >= 0) ? {threshold: this.bScrollObject.pullUpLoad} : false
      })
      //滚动监听
      if (this.bScrollObject.probeType === 2 || this.bScrollObject.probeType === 3) {
        this.bScroll.on('scroll', (position) => {
          if (this.bScrollObject.showBackToTop) {
            this.showBackToTop = (Math.abs(position.y) > Math.abs(this.bScrollObject.distance));
          }
          this.$emit('scrollMonitor', position);
        })
      }
      //下拉监听
      if (this.bScrollObject.pullDownRefresh && this.bScroll) {
        this.bScroll.on('pullingDown', () => {
          this.setDownTipText(PHASE.fetching);
          //执行请求方法

          this.setDownTipText(PHASE.succeed);
          this.bScroll.finishPullDown();
        })
        this.bScroll.on('enterThreshold', () => {
          this.setDownTipText(PHASE.moving.enter)
        })
        this.bScroll.on('leaveThreshold', () => {
          this.setDownTipText(PHASE.moving.leave)
        })
      }
      //上拉监听
      if (this.bScrollObject.pullUpLoad >= 0 && this.bScroll) {
        this.bScroll.on('pullingUp', () => {
          //执行请求方法
          this.$emit('pullingUp', this.bScroll.finishPullUp);
        })
      }
    },
    refresh() {
      return this.bScroll && this.bScroll.refresh()
    },
    backToTop() {
      this.scrollTo(0, 0, this.bScrollObject.scrollToTime);
    },
    scrollTo(x = 0, y = 0, time = 0) {
      this.bScroll && this.bScroll.scrollTo(x, y, time);
    },
    scrollToElement(el, time = 0, offsetX, offsetY) {
      this.bScroll.scrollToElement(el, time, offsetX, offsetY);
    },
    getScrollY() {
      return this.bScroll ? this.bScroll.y : 0;
    },
    setDownTipText(phase = PHASE.default) {
      const TEXTS_MAP = {
        'enter': `${ARROW_BOTTOM} Pull down`,
        'leave': `${ARROW_UP} Release`,
        'fetching': 'Loading...',
        'succeed': 'Refresh succeed'
      }
      this.downTipText = TEXTS_MAP[phase]
    }
  }
}
</script>

<style scoped>
.scroll-wrapper {
  overflow: hidden;
}

.pull-down-wrapper {
  position: absolute;
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
  transform: translateY(-100%) translateZ(0);
  text-align: center;
  color: #999;
}

.back-to-top {
  position: fixed;
  right: 5px;
  bottom: 50px;
}

.back-to-top img {
  width: 45px;
  height: 45px;
}
</style>
